classdef CSTDataLoader<handle
    %  作者：姚晨
    %  创建日期：2021/11/29
    
    %% 共有属性
    properties(Access=public)
        label
        src
        dst
        sigma
        nfft
        win_type
    end
    %% 私有属性
    properties(Access=private)
        target_name
        num_freq
        batch_size
        save_mode
        txt_name
        DATA
    end
    %% 公有函数
    methods(Access=public)
        function obj = CSTDataLoader(src, dst, target_name, args)
            arguments
                % Positional arguments
                src     % cst仿真数据存放路径
                dst     % 处理结果保存路径
                target_name % 目标名称
                
                % Key-Value arguments
                args.num_freq = 129; % 仿真的宽带频段内的离散点数
                args.batch_size = 1024;               
                args.sigma = 0; % noise power
                args.nfft = 256;             
                args.save_mode = "all-in-one"
                args.txt_name = struct("H",{"farfield_HP.txt"},"V",{"farfield_VP.txt"})
                args.win_type = "rectwin";
            end
            
            % 初始化类属性
            obj.dst = dst;
            obj.src = src;
            obj.target_name = target_name;           
            obj.sigma = args.sigma;
            obj.nfft = args.nfft;
            obj.num_freq = args.num_freq;
            obj.batch_size = args.batch_size;
            obj.save_mode = args.save_mode;
            obj.txt_name = args.txt_name;
            obj.win_type = args.win_type;
            
            hrrp_from_txt(obj);
        end
        function [lb, data] = read(obj, phi_range, theta_range)
            [lb, data] = pick_data(obj, phi_range, theta_range);
            %hrrp = cal_hrrp(obj, data);
        end
        function save(obj, phi_range, theta_range, foldername)
            arguments
                obj
                phi_range
                theta_range
                foldername = [];
            end
            [lb, data] = pick_data(obj, phi_range, theta_range);
            hrrp = cal_hrrp(obj, data);
            switch obj.save_mode
                case "all-in-one"                  
                    save_all_in_one(obj, hrrp, foldername);
                case "seperate"
                    save_seperate(obj, lb, hrrp, foldername);
            end
        end       
        function plot(obj, phi, theta, plot_type)
            arguments
                obj
                phi
                theta
                plot_type = 'abs';
            end
            epi = 1e-5;
            idx_seq = bitand(abs(obj.label(1, :)-phi)<epi, abs(obj.label(2, :)-theta)<epi);
            idx = find(idx_seq==1);
            
            plot_data = obj.DATA(:, :, idx);
            hrrp = cal_hrrp(obj, plot_data);
            figure;
            switch plot_type
                case 're'%real part
                    plot(real(hrrp));
                case 'im'
                    plot(imag(hrrp));
                case 'abs'
                    plot(abs(hrrp));
                case 'db'
                    plot(db(hrrp));
                case 'ph'%phase
                    plot(unwrap(angle(hrrp)));
                otherwise 
                    error('No such a plot type:'+string(plot_type));
            end
                
            
        end
    end
    %% 私有函数
    methods(Access=private)
        function hrrp_from_txt(obj)
            % get polarization type from <obj.txt_name>[struct]
            fields = fieldnames(obj.txt_name);      
            % loop over all polarization type
            for i = 1: length(fields)
                filename = eval("obj.txt_name."+fields{i});
                filepath = fullfile(obj.src, filename);              
                [obj.label, data_array] = HRRP_from_RCS(obj, filepath);
                obj.DATA = cat(2, obj.DATA, data_array);
            end        
        end
        function [lb, data] = pick_data(obj, phi_range, theta_range)
            col_idx_in_phi = bitand(obj.label(1, :)>=phi_range(1), obj.label(1, :)<phi_range(2));
            col_idx_in_theta = bitand(obj.label(2, :)>=theta_range(1), obj.label(2, :)<theta_range(2));
            col_idx = bitand(col_idx_in_theta, col_idx_in_phi);
            
            lb = obj.label(:, col_idx);
            data = obj.DATA(:, :, col_idx);
        end
        function [label, data_array] = HRRP_from_RCS(obj, filepath)
            % 打开文本文件。
            fileID = fopen(filepath,'r');
            fseek(fileID,0,'eof');
            
            %文本字节数目
            n_bytes = ftell(fileID);
            fseek(fileID,0,'bof');
            
            % 标题行序号
            header_index = 1;
            
            % 每次读取行数
            rows_read = obj.batch_size*obj.num_freq;
            
            % 初始化读取的起始位置
            pos = 0;
                  
            % hrrp对应的角度信息
            label = [];
            % 如果save_mode是"all-in-one",用hrrp_array.
            data_array = [];
            % 根据格式读取数据列。
            formatSpec = '%f %f %f %f %f %f %f %f %f %[^\n\r]';
            
            % 开始读取数据
            while pos<n_bytes
                % dataArray是一个元胞数组，最后一列是为空；
                [dataArray, pos] = textscan(fileID, formatSpec, rows_read, ...
                    'Delimiter', '',  ...
                    'WhiteSpace', '',  ...
                    'TextType', 'string',  ...
                    'EmptyValue', NaN,  ...
                    'HeaderLines', header_index,  ...
                    'ReturnOnError', false,  ...
                    'EndOfLine', '\r\n');
                
                
                % 从txt读取的远场RCS数据，其中第一列是频率
                farfield = cat(2,dataArray{1:end-1});
                
                % 每个观测频点对应的角度信息
                phi_array = reshape(farfield(:,2), obj.num_freq, []);%size：num_freq*batchsize
                theta_array = reshape(farfield(:,3), obj.num_freq, []);
                % 当前batch中每个样本的观测角度[phi;theta];
                label_ang = [mean(phi_array);mean(theta_array)];
                % 更新label值
                label = cat(2, label, label_ang);
                % 获得H和V通道的复数信号(SCB)
                cplx_rcs_h = reshape(farfield(:,6)+1j*farfield(:,7), obj.num_freq, 1, []);
                cplx_rcs_v = reshape(farfield(:,8)+1j*farfield(:,9), obj.num_freq, 1, []);
                
                % concatenate data of different channel
                cplx_rcs = cat(2, cplx_rcs_h, cplx_rcs_v);
                               
                % concatenate data of different batch
                data_array = cat(3, data_array, cplx_rcs);
            end   
        end
        function hrrp = cal_hrrp(obj, data)
            % 默认加hanning窗处理
            win_cmd = obj.win_type+"("+obj.num_freq+")";
            win = eval(win_cmd);
            % 计算hrrp
            hrrp = fftshift(ifft(data.*win, obj.nfft),1);
            hrrp = CSTDataLoader.awgn(hrrp, obj.sigma);
        end
        function save_all_in_one(obj, HRRP, savefolder)
            savepath = fullfile(obj.dst, savefolder);
            if ~isfolder(savepath)
                mkdir(savepath)
            end
            save(fullfile(savepath, obj.target_name+".mat"), "HRRP");
        end
        function save_seperate(obj, label, hrrp, savefolder)
            savefolder = fullfile(obj.dst, savefolder, obj.target_name);
            if ~isfolder(savefolder)
                mkdir(savefolder)
            end
            for i = 1:size(hrrp, 3)
                % 根据角度信息，命名mat文件
                name = sprintf('%s_%s.mat', num2str(label(1,i)), num2str(label(2,i)));

                HRRP = hrrp(:, :, i);
                savepath = fullfile(savefolder, name);
                save(savepath,'HRRP');
            end         
        end
    end
    
    methods(Static)
        function data_n = awgn(data, sigma)
            data_n = data + sigma*randn(size(data)) + 1j*sigma*randn(size(data));
        end
    end
end


